#include "net.h"
#include "flow.h"
#include "raw_socket.h"

void init_flow_state(p_main_flow mflow)
{
	memset(&(mflow->m_flow_state), 0, sizeof(flow_state));
}


uint16_t init_main_flow(p_main_flow mflow) 
{
	p_socket_io sock = &(mflow->m_socket_io);
	p_socket_state sstate = &(mflow->m_flow_state.sstate);
	init_sockaddr_in_2(&(sock->local_addr), sstate->local_ip, sstate->local_port, 1);
	init_sockaddr_in_2(&(sock->remote_addr), sstate->remote_ip, sstate->remote_port, 1);
	init_ip_mreq_2(&(sock->mreq), sstate->local_ip, sstate->mreq_ip);
	mflow->m_input  = send_msg;
	mflow->m_output = recv_msg;

	if (mflow->m_socket_io.s_type == socket_raw) {
		mflow->m_input = raw_send_msg;
		mflow->m_output = raw_recv_msg;
		return init_raw_socket(&(mflow->m_socket_io));
	}
	return init_udp(&(mflow->m_socket_io));
}

uint16_t send_msg(p_socket_io sock, char* buf, uint16_t* size)
{
	int _size = 0;
	socklen_t socklen = sizeof(sock->remote_addr);
	_size = sendto(sock->fd, buf, *size, 0, (struct sockaddr*)&(sock->remote_addr), socklen);
	if (_size != (*size)){
		return ERR_SEND;
	}
	return NO_ERR;
}

uint16_t recv_msg(p_socket_io sock, char* buf, uint16_t* size)
{
	socklen_t socklen = sizeof(sock->remote_addr);
	int _size = 0;
	_size = recvfrom(sock->fd, buf, *size, 0,(struct sockaddr *)&sock->remote_addr, &socklen);
	*size = _size;
	return NO_ERR;
}

void main_loop(p_main_flow mflow)
{
	//struct ethhdr *eth;
	//uint16_t eth_p_ip = htons(ETH_P_IP);
	char buf[MAX_MESSAGE_LEN] = {0};
	uint16_t data_size = 0;
	uint16_t err;
	int i;
	//struct timeval tv,now;
	struct timespec _old = { 0, 0 };
	struct timespec _new = { 0, 0 };
	uint16_t offs = 0;
	if (mflow->m_socket_io.s_type == socket_raw) {
		offs = get_data_offset();
		raw_pre_send_buffer(&(mflow->m_socket_io), buf, mflow->m_data_size+offs);
	}
	for (i = offs; i < mflow->m_data_size+offs+1; i++) {
		buf[i] = i%256;
	}
	while(!mflow->m_bstop)
	{
		data_size = mflow->m_data_size+offs;
		if (SOCKET_FLOW_TYPE_CLIENT == mflow->m_socket_io.flow_type ||
				SOCKET_TCP_TYPE_CLIENT == mflow->m_socket_io.flow_type)
		{
			if (mflow->m_check_pause && mflow->m_check_pause(mflow)) {
				sleep(1);
				continue;
			}
			if (mflow->m_fill_data) {
				mflow->m_fill_data(buf, data_size);
			}
			clock_gettime(CLOCK_REALTIME, &_old);
			if (mflow->m_input) {
				err = mflow->m_input(&(mflow->m_socket_io), buf, &data_size);
				if (err == NO_ERR) {
					mflow->m_flow_state.tx_pkt += 1;
					mflow->m_flow_state.tx_byte += data_size;
				} else {
					mflow->m_flow_state.err_tx_pkt += 1;
					mflow->m_flow_state.err_tx_byte += data_size;
				}

				//update_input_state(mflow, 1, data_size, err);
			}
			if (mflow->m_flow_data_direct != flow_data_loop) {
				continue;
			}
			if (mflow->m_output) {
				err = mflow->m_output(&(mflow->m_socket_io), buf, &data_size);
			} else {
				continue;
			}
			clock_gettime(CLOCK_REALTIME, &_new);
			mflow->m_loop_delay = (_new.tv_sec-_old.tv_sec) * 1000000U + (_new.tv_nsec - _old.tv_nsec)/1000;
			mflow->m_loop_delay_max = mflow->m_loop_delay > mflow->m_loop_delay_max ? mflow->m_loop_delay : mflow->m_loop_delay_max;
			if (data_size == 0) {
				mflow->m_loop_delay_max = 999999;
				continue;
			}
			if (mflow->m_check_data)
			{
				err = mflow->m_check_data(buf, data_size);
			} else 
			{
				err = NO_ERR;
			}
			if (err == NO_ERR) {
				mflow->m_flow_state.rx_pkt += 1;
				mflow->m_flow_state.rx_byte += data_size;
			} else {
				mflow->m_flow_state.err_rx_pkt += 1;
				mflow->m_flow_state.err_rx_byte += data_size;
			}
			//update_output_state(mflow, 1, data_size, err);
			usleep(100);
		} else if (SOCKET_FLOW_TYPE_SERVER == mflow->m_socket_io.flow_type) 
		{
			if (mflow->m_output) {
				err = mflow->m_output(&(mflow->m_socket_io), buf, &data_size);
			} else continue;
			if (data_size == 0) continue;
			err = NO_ERR;
			if (mflow->m_check_data)
			{
				err = mflow->m_check_data(buf, data_size);
			}
			if (err == NO_ERR) {
				mflow->m_flow_state.rx_pkt += 1;
				mflow->m_flow_state.rx_byte += data_size;
			} else {
				mflow->m_flow_state.err_rx_pkt += 1;
				mflow->m_flow_state.err_rx_byte += data_size;
			}
			//update_output_state(mflow, 1, data_size, err);

			switch (mflow->m_flow_data_direct)
			{
				case flow_data_back:
					if (mflow->m_input) {
						if (mflow->m_socket_io.s_type == socket_raw) {
							raw_back_pre_buffer(buf, data_size);
						}
						err = mflow->m_input(&(mflow->m_socket_io), buf, &data_size);
						if (err == NO_ERR) {
							mflow->m_flow_state.tx_pkt += 1;
							mflow->m_flow_state.tx_byte += data_size;
						} else {
							mflow->m_flow_state.err_tx_pkt += 1;
							mflow->m_flow_state.err_tx_byte += data_size;
						}
						//update_input_state(mflow, 1, data_size, err);
					}
					break;
				case flow_data_drop:
				default:
					break;
			}
		}
	}
	//fclose(mflow->m_socket_io.fd);
}



